package com.sea.base.utils.voice

import android.media.MediaRecorder
import android.os.Build
import androidx.lifecycle.Lifecycle
import com.sea.base.ext.global.createSecondsCountdownTimer
import com.sea.base.ext.global.currentDiffTimeSeconds
import com.sea.base.ext.global.getCurrentMillis
import com.sea.base.ext.global.log
import com.sea.base.ext.global.singleApplication
import com.sea.base.ext.global.toast
import com.sea.base.ext.obs.doOnDestroyed
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean

/**
 * Author: Wu Chang
 *
 * Date: 2023/8/31 15:39
 */
class MediaRecordUtil(
    lifecycle: Lifecycle,
    private val maxRecordTimeSeconds: Int,
    private val onRecordTimer: (currentTimeSeconds: Int) -> Unit,
    private val onRecordFail: (failMsg: String) -> Unit,
    private val onRecordSuccess: (path: String, timeSeconds: Int) -> Unit,
) {
    private val tag = "MediaRecordUtil"
    private var mediaRecorder: MediaRecorder? = null
    private var filePath: String? = null

    private val fileRoot = File(singleApplication.filesDir, "audioRecord").also { it.mkdirs() }

    private val _isRecording = AtomicBoolean()
    val isRecording get() = _isRecording.get()

    /**
     * 录音限制的计时器
     */
    private val timer = createSecondsCountdownTimer(lifecycle, maxRecordTimeSeconds,
        onTickCallback = { onRecordTimer.invoke(currentDiffTimeSeconds) },
        onFinishCallback = { finish() })

    init {
        lifecycle.doOnDestroyed { cancel() }
    }

    fun start() {
        try {
            _isRecording.set(true)
            filePath = File(fileRoot, "Record_${getCurrentMillis()}.mp4").absolutePath
            mediaRecorder = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) MediaRecorder(singleApplication) else MediaRecorder()).apply {
                setAudioSource(MediaRecorder.AudioSource.MIC)
                setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
                setAudioEncoder(MediaRecorder.AudioEncoder.AAC_ELD)
                setOutputFile(filePath)
                setMaxDuration(maxRecordTimeSeconds * 1000)
                prepare()
                start()
            }
            timer.start()
            "开始录音，路径：$filePath".log(tag)
        } catch (e: Throwable) {
            e.printStackTrace()
            cancel()
            onRecordFail.invoke(e.toString())
        }
    }

    /**
     * 取消录音
     */
    fun cancel() {
        release()
        filePath?.let { filePath ->
            val f = File(filePath)
            if (f.exists()) {
                f.delete()
                "取消并删除录音".log(tag)
            }
        }
    }

    private fun release() {
        try {
            _isRecording.set(false)
            mediaRecorder?.stop()
            mediaRecorder?.release()
            mediaRecorder = null
            timer.cancel()
        } catch (e: Throwable) {
            e.printStackTrace()
            onRecordFail.invoke(e.toString())
        }
    }

    /**
     * 完成录音
     */
    fun finish() {
        if (!isRecording) return
        release()
        if (timer.currentDiffTimeSeconds <= 1) {
            "录音时间太短，请重试".toast()
            cancel()
            onRecordFail.invoke("录音时间太短")
            return
        }
        onRecordSuccess.invoke(filePath!!, timer.currentDiffTimeSeconds)
        "完成录音".log(tag)
    }
}